package com.tbl.modules.wms.service.Impl.instorage;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.tbl.common.utils.DateUtils;
import com.tbl.common.utils.PageTbl;
import com.tbl.common.utils.PageUtils;
import com.tbl.common.utils.StringUtils;
import com.tbl.modules.platform.dao.system.UserDAO;
import com.tbl.modules.wms.constant.EmumConstant;
import com.tbl.modules.wms.dao.baseinfo.*;
import com.tbl.modules.wms.dao.instorage.InstorageDAO;
import com.tbl.modules.wms.dao.instorage.InstorageDetailDAO;
import com.tbl.modules.wms.dao.inventory.InventoryInDAO;
import com.tbl.modules.wms.dao.storageinfo.StorageInfoDAO;
import com.tbl.modules.wms.entity.baseinfo.*;
import com.tbl.modules.wms.entity.instorage.Instorage;
import com.tbl.modules.wms.entity.instorage.InstorageDetail;
import com.tbl.modules.wms.entity.inventory.InventoryIn;
import com.tbl.modules.wms.entity.storageinfo.StorageInfo;
import com.tbl.modules.wms.service.Impl.baseinfo.ShelfServiceImpl;
import com.tbl.modules.wms.service.Impl.webserviceImpl.WmsServiceImpl;
import com.tbl.modules.wms.service.instorage.InstorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 入库管理
 * @author 70486
 */
@Service
public class InstorageServiceImpl extends ServiceImpl<InstorageDAO, Instorage> implements InstorageService {

    /**
     * 入库管理-订单
     */
    @Autowired
    private InstorageDAO instorageDAO;
    /**
     * 入库管理-订单详情
     */
    @Autowired
    private InstorageDetailDAO instorageDetailDAO;
    /**
     * 库存
     */
    @Autowired
    private StorageInfoDAO storageInfoDAO;
    /**
     * 仓库
     */
    @Autowired
    private WarehouseDAO warehouseDAO;
    /**
     * 行车
     */
    @Autowired
    private CarDAO carDAO;
    /**
     * 库位信息
     */
    @Autowired
    private ShelfDAO shelfDAO;
    /**
     * 盘具信息
     */
    @Autowired
    private DishDAO dishDAO;
    /**
     * 厂区
     */
    @Autowired
    private FactoryAreaDAO factoryAreaDAO;
    /**
     * 用户
     */
    @Autowired
    private UserDAO userDAO;
    /**
     * 入库日志登记表
     */
    @Autowired
    private InventoryInDAO inventoryInDAO;
    /**
     * 库位信息
     */
    @Autowired
    private ShelfServiceImpl shelfImpl;
    /**
     * 接口调用
     */
    @Autowired
    private WmsServiceImpl wmsServiceImpl;

    /**
     * 订单展示----获取列表数据
     * @param pageTbl 分页工具类
     * @param map 参数条件
     * @return PageUtils
     */
    @Override
    public PageUtils getPageList(PageTbl pageTbl, Map<String, Object> map) {
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), pageTbl.getSortname(), "asc".equalsIgnoreCase(pageTbl.getSortorder()));
        return new PageUtils(page.setRecords(instorageDAO.getPageList(page, map)));
    }

    /**
     * 订单展示----获取详情列表数据
     * @param pageTbl 分页工具类
     * @param map 参数条件
     * @return PageUtils
     */
    @Override
    public PageUtils getPageDetgailList(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "t1.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(instorageDAO.getPageDetgailList(page, map)));
    }

    /**
     * 装包管理----获取详情列表数据
     * @param pageTbl 分页工具类
     * @param map 参数条件
     * @return PageUtils
     */
    @Override
    public PageUtils getPackDetailPageList(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "a.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(instorageDAO.getPackDetailPageList(page, map)));
    }

    /**
     * 装包管理----根据主键获取详情数据
     * @param id 入库明细主键
     * @return InstorageDetail
     */
    @Override
    public InstorageDetail getEntityById(Long id) {
        return instorageDetailDAO.selectById(id);
    }

    /**
     * 装包管理----点击确认改变状态
     * @param lstInstorageDetail 入库明细
     */
    @Override
    public void packDetailConfirm(List<InstorageDetail> lstInstorageDetail) {
    	instorageDAO.packDetailConfirm(lstInstorageDetail);
    }

    /**
     * 装包管理----导出
     * @param map 条件参数
     * @return List<InstorageDetail>
     */
    @Override
    public List<InstorageDetail> getDetailExcelList(Map<String, Object> map) {
        return instorageDAO.getDetailExcelList(map);
    }

    /**
     * 吊装台账----导出
     * @param map 条件
     * @return List<InstorageDetail>
     */
    @Override
    public List<InstorageDetail> getAccountHoistExcelList(Map<String, Object> map) {
        return instorageDAO.getAccountHoistExcelList(map);
    }

    /**
     * 包装台账----导出
     * @param map 条件
     * @return List<InstorageDetail>
     */
    @Override
    public List<InstorageDetail> getAccountPackingExcelList(Map<String, Object> map) {
        return instorageDAO.getAccountPackingExcelList(map);
    }

    /**
     * 入库----获取列表数据
     * @param pageTbl 分页工具
     * @param map 参数条件
     * @return PageUtils
     */
    @Override
    public PageUtils getPagePackageList(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "a.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        if (map.get("state")!=null&&!"".equals(map.get("state").toString())){
            map.put("state", Arrays.stream(map.get("state").toString().split(",")).map(Long::parseLong).collect(Collectors.toList()));
        }else {
            map.remove("state");
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(instorageDAO.getPagePackageList(page, map)));
    }

    /**
     * 入库----获取仓库列表
     * @param code 仓库编码
     * @return List<Warehouse> 仓库列表
     */
    @Override
    public List<Warehouse> getWarehouseList(String code) {
        return instorageDAO.getWarehouseList(Arrays.asList(code.split(",")));
    }

    /**
     * 入库----获取仓库下的行车列表
     * @param id 仓库主键
     * @param org 厂区编码
     * @return List<Car> 行车列表
     */
    @Override
    public List<Car> getCarList(Long id,String org) {
        return instorageDAO.getCarList(id,org);
    }
    
    /**
     * 入库----获取仓库下的行车列表
     * @param factoryCode 厂区编码
     * @return List<Car> 行车列表
     */
    @Override
    public List<Car> findCarList(String factoryCode) {
        return instorageDAO.findCarList(factoryCode);
    }

    /**
     * 入库----根据详情主键获取详情信息
     * @param id 标签初始化表主键
     * @return InstorageDetail
     */
    @Override
    public InstorageDetail getDetailById(Long id) {
        return instorageDAO.getDetailById(id);
    }

    /**
     * 入库----获取到推荐库位
     * @param code 仓库编码
     * @param factoryCode 厂区编码
     * @return String 库位编码
     */
    @Override
    public String getRecommendShelf(String code,String factoryCode) {
        return StringUtils.join(instorageDAO.getRecommendShelf(code, factoryCode).stream().map(Shelf::getCode).collect(Collectors.toList()), ",");
    }

    /**
     * 入库----开始入库，更新详情表信息
     * @param instorageDetail 入库明细
     * @return boolean
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateDetail(InstorageDetail instorageDetail) {
        Car car = carDAO.selectById(instorageDetail.getCarId());
        instorageDetail.setWarehouseCode(warehouseDAO.selectById(instorageDetail.getWarehouseId()).getCode());
        instorageDetail.setCarCode(car.getCode());
        instorageDetail.setStartStorageTime(new Date());
        instorageDetail.setState(3);
        instorageDetail.setFactoryCode(factoryAreaDAO.selectById(instorageDetail.getFactoryCode()).getCode());
        //入库中
        car.setState(Long.valueOf(EmumConstant.carState.INSTORAGING.getCode()));
        carDAO.updateById(car);
        return instorageDetailDAO.updateById(instorageDetail)>0;
    }

    /**
     * 入库----入库确认获取选择的库位列表
     * @param pageTbl 分页工具页面类
     * @param map 条件参数
     * @return PageUtils
     */
    @Override
    public PageUtils selectUnbindShelf(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "t1.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(instorageDAO.selectUnbindShelf(page, map)));
    }

    /**
     * 手动入库----获取选择的库位列表
     * @param pageTbl 分页工具页面类
     * @param map 参数条件
     * @return PageUtils
     */
    @Override
    public PageUtils selectManualShelf(PageTbl pageTbl, Map<String, Object> map) {
        String sortName = pageTbl.getSortname();
        String sortOrder = pageTbl.getSortorder();
        if (StringUtils.isEmptyString(sortName)) {
            sortName = "t1.id";
        }
        if (StringUtils.isEmptyString(sortOrder)) {
            sortOrder = "desc";
        }
        Page page = new Page(pageTbl.getPageno(), pageTbl.getPagesize(), sortName, "asc".equalsIgnoreCase(sortOrder));
        return new PageUtils(page.setRecords(instorageDAO.selectManualShelf(page, map)));
    }

    /**
     * 入库----导出
     * @param map 条件参数
     * @return List<InstorageDetail>
     */
    @Override
    public List<InstorageDetail> getPackageInExcelList(Map<String, Object> map) {
        return instorageDAO.getPackageInExcelList(map);
    }

    /**
     * 入库---- 入库确认
     * @param id 标签初始化主键
     * @param shelfId 库位主键
     * @param userId 用户主键
     * @param time 事务处理日期
     * @param factoryId 厂区主键
     * @param warehouseId 仓库主键
     * @return Map<String,Object>
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String,Object> confirmInstorage(Long id, Long shelfId, Long userId, String time, Long factoryId, Long warehouseId) {
        Map<String, Object> resultMap = Maps.newHashMap();

    	InstorageDetail instorageDetail = instorageDetailDAO.selectById(id);
        List<StorageInfo> lstStorageInfo = storageInfoDAO.selectList(new EntityWrapper<StorageInfo>()
                .eq("QACODE", instorageDetail.getQaCode()));
        //如果存在了，则不能重复新增
        if(lstStorageInfo!=null&&lstStorageInfo.size()>0) {
            return new HashMap<String, Object>(2){{
                put("result", false);
                put("msg", "货物已入库，不需要再次入库！");
            }};
        }

    	Instorage instorage = instorageDAO.selectById(instorageDetail.getPId());
    	Shelf shelf = shelfDAO.selectById(shelfId);
        Warehouse warehouse = warehouseDAO.selectById(warehouseId);
        FactoryArea factoryArea = factoryAreaDAO.selectById(factoryId);

        instorageDetail.setWarehouseCode(warehouse.getCode());
        instorageDetail.setFactoryCode(factoryArea.getCode());
    	//获取流水号
    	List<FactoryArea> factorySerialnumList = factoryAreaDAO.selectByMap(new HashMap<String,Object>(){{
    		put("CODE",instorageDetail.getFactoryCode());
    	}});
    	String serialnum = factorySerialnumList.size() >0 ? factorySerialnumList.get(0).getSerialnum() : "";
        serialnum = StringUtils.isNotEmpty(serialnum) ? String.format("%04d", Integer.parseInt(serialnum)+1) : "0001";

    	Dish dish = dishDAO.selectOne(new Dish() {{
    		setCode(instorageDetail.getDishnumber());
    	}});
    	//成品电缆盘号
        String drumno;
        if (dish == null || "1327100013".equals(dish.getCode()) || "F003".equals(instorageDetail.getWarehouseCode())){
            drumno = "";
        }else{
            drumno = shelf.getCodeComplete().charAt(0)+ ("铁木盘".equals(dish.getDrumType()) ? "1" : "全木盘".equals(dish.getDrumType()) ? "2" : "3") +
            new DecimalFormat("000").format(Long.parseLong(dish.getOuterDiameter() != null ? dish.getOuterDiameter() : "0")/10) +
            DateUtils.getDays().substring(2) + serialnum;
        }

        //入库日志
        InventoryIn inventoryIn = new InventoryIn();
        inventoryIn.setOrg(factoryArea.getCode());
        inventoryIn.setModel(instorageDetail.getDishnumber());
        inventoryIn.setDishtype(dish == null?"":dish.getDrumType());
        inventoryIn.setDishsize(dish == null?"":dish.getOuterDiameter());
        inventoryIn.setRfid(instorageDetail.getRfid());
        inventoryIn.setWarehousecode(warehouse.getCode());
        inventoryIn.setShelfcode(shelf.getCode());
        inventoryIn.setInStorageId(userId);
        inventoryIn.setOuterDiameter(dish == null?0:Long.parseLong(StringUtils.isNotBlank(dish.getOuterDiameter())?dish.getOuterDiameter():"0"));
        inventoryIn.setDrumType("手动入库");
        inventoryIn.setMaterialcode(serialnum);
        inventoryIn.setMaterialname(drumno);
        inventoryIn.setQacode(instorageDetail.getQaCode());
        inventoryInDAO.insert(inventoryIn);

    	try {
            //入库人
            String userno = userDAO.selectById(userId).getUsername();
            //接口执行成功与否
            boolean interfaceExecuteResult;
            Map<String,Object> params = new HashMap<>();
            //调EBS外采入库接口
    		if(instorageDetail.getStoragetype()==2) {
    	    	params.put("line",new HashMap<String,Object>(10) {{
                    //入库厂区编码
    	    		put("orgid",instorageDetail.getOrg());
                    //质保号
    	    		put("qacode",instorageDetail.getQaCode());
                    //报验单号
    	    		put("inspectno",instorageDetail.getInspectno());
                    //入库仓库
    	    		put("worehouse",instorageDetail.getWarehouseCode());
                    //库位
    	    		put("location",shelf.getCodeComplete());
                    //盘号
    	    		put("panno",drumno);
                    //批次号
    	    		put("batchname",instorageDetail.getBatchNo());
                    //事务处理日期
    	    		put("trans_date",time);
                    put("userno", userno);
    	    	}});
    	    	//实时调用接口
    	    	String returnInfo = wmsServiceImpl.FEWMS025(params, instorageDetail.getQaCode(), instorageDetail.getBatchNo());
                returnInfo = returnInfo.replace(" ", "");
                //接口执行结果
                interfaceExecuteResult = returnInfo.contains("<code>0</code>") || returnInfo.contains("\"code\":0")
                        || returnInfo.contains("S000A000");
                //接口执行失败，直接返回，不做下面的任何更新操作，因为失败后，用户还需要再次点击，成功后才能更新
                if (!interfaceExecuteResult){
                    //根据接口执行结果把实时结果（返回报文）展示到前台界面
                    resultMap.put("result", false);
                    resultMap.put("msg", "接口执行失败：" + returnInfo);
                    return resultMap;
                }else {
                    resultMap.put("result", true);
                    resultMap.put("msg", "入库成功！");
                }
    		}else if(instorageDetail.getStoragetype()==0) {
    			//调MES入库接口
    			params.put("orgid", instorageDetail.getFactoryCode());
                params.put("busdate", time);
                params.put("userno", userno);
    			params.put("batches", new HashMap<String,Object>(){{
    				put("batch",new HashMap<String,Object>(){{
    					put("batchno",instorageDetail.getBatchNo());
    					put("invlocation",shelf.getCodeComplete());
                        //成品电缆盘号
    					put("drumno",drumno);
    				}});
    			}});
                //实时调用接口
                String returnInfo = wmsServiceImpl.FEMES001(params, instorageDetail.getQaCode(), instorageDetail.getBatchNo());
                returnInfo = returnInfo.replace(" ", "");
                //接口执行结果
                interfaceExecuteResult = returnInfo.contains("<code>0</code>") || returnInfo.contains("\"code\":0")
                        || returnInfo.contains("S000A000");
                //接口执行失败，直接返回，不做下面的任何更新操作，因为失败后，用户还需要再次点击，成功后才能更新
                if (!interfaceExecuteResult){
                    //根据接口执行结果把实时结果（返回报文）展示到前台界面
                    resultMap.put("result", false);
                    resultMap.put("msg", "接口执行失败：" + returnInfo);
                    return resultMap;
                }else {
                    resultMap.put("result", true);
                    resultMap.put("msg", "入库成功！");
                }
    		}else if(instorageDetail.getStoragetype()==1){
                //调EBS销售退货入库接口
    			params.put("line", new HashMap<String,Object>(12){{
                    //组织id
    				put("orgid",instorageDetail.getOrg());
                    //物料编码
    				put("itemnumber",instorageDetail.getMaterialCode());
                    //客户id
    				put("customerid",instorageDetail.getCustomerid());
                    //员工编号
    				put("employeenum",userno);
                    //数量
                    put("quantity",instorageDetail.getMeter());
                    //事务处理日期
    				put("transdate",time);
                    //库位编码
                    put("locatornum",shelf.getCodeComplete());
                    //销售订单头id
                    put("oeheaderid",instorageDetail.getOeheader());
                    //销售订单行id
                    put("oelineid",instorageDetail.getOeline());
                    //批次号
                    put("lotnumber",instorageDetail.getBatchNo());
                    //质保号
                    put("qacode",instorageDetail.getQaCode());
                    //盘号
                    put("dishcode",drumno);
    			}});
                //实时调用接口
                String returnInfo = wmsServiceImpl.FEWMS024(params, instorageDetail.getQaCode(), instorageDetail.getBatchNo());
                returnInfo = returnInfo.replace(" ", "");
                //接口执行结果
                interfaceExecuteResult = returnInfo.contains("<code>0</code>") || returnInfo.contains("\"code\":0")
                        || returnInfo.contains("S000A000");
                //接口执行失败，直接返回，不做下面的任何更新操作，因为失败后，用户还需要再次点击，成功后才能更新
                if (!interfaceExecuteResult){
                    //根据接口执行结果把实时结果（返回报文）展示到前台界面
                    resultMap.put("result", false);
                    resultMap.put("msg", "接口执行失败：" + returnInfo);
                    return resultMap;
                }else {
                    resultMap.put("result", true);
                    resultMap.put("msg", "入库成功！");
                }
    		}
		} catch (Exception e) {
			e.printStackTrace();
            resultMap.put("result", false);
            resultMap.put("msg", "接口执行失败：系统错误，请联系管理员！");
            return resultMap;
		}

        //更新流水号
        if(factorySerialnumList.size()>0) {
            FactoryArea fa = factorySerialnumList.get(0);
            fa.setSerialnum(serialnum);
            factoryAreaDAO.updateById(fa);
        }

    	instorageDetail.setDishcode(drumno);
        instorageDetail.setShelfCode(shelf.getCode());
        instorageDetail.setInStorageId(userId);
        instorageDetail.setInstorageTime(new Date());
        instorageDetail.setState(EmumConstant.instorageDetailState.STORAGED.getCode());
        instorageDetailDAO.updateById(instorageDetail);

        StorageInfo storageInfo = new StorageInfo();
        storageInfo.setMaterialCode(instorageDetail.getMaterialCode());
        storageInfo.setBatchNo(instorageDetail.getBatchNo());
        storageInfo.setQaCode(instorageDetail.getQaCode());
        storageInfo.setShelfCode(shelf.getCode());
        storageInfo.setWarehouseCode(instorageDetail.getWarehouseCode());
        storageInfo.setMeter(instorageDetail.getMeter());
        storageInfo.setRfid(instorageDetail.getRfid());
        storageInfo.setInStorageTime(new Date());
        storageInfo.setOrg(instorageDetail.getFactoryCode());
        storageInfo.setSalesCode(instorageDetail.getSalesCode());
        storageInfo.setSalesName(instorageDetail.getSalesName());
        storageInfo.setInStorageId(userId);
        storageInfo.setDishnumber(instorageDetail.getDishnumber());
        storageInfo.setOrderline(instorageDetail.getOrderline());
        storageInfo.setOrderno(instorageDetail.getOrdernum());
        if(instorage!=null){
            storageInfo.setEntityNo(instorage.getEntityNo());
        }
        storageInfoDAO.insert(storageInfo);
        
        //库位状态为不可用
        shelfImpl.setShelfState(shelf.getCode(), shelf.getFactoryCode(), shelf.getWarehouseCode(),0);
        
        return resultMap;
    }

}
